package com.hua.customviews.widget

import android.content.Context
import android.util.AttributeSet
import android.view.MotionEvent
import android.view.ViewParent
import androidx.constraintlayout.widget.ConstraintLayout
import kotlin.math.abs

/**
 * 用于专门处理事件的ConstraintLayout
 * @author hua
 * date: 2023年1月31日
 */
@Suppress("MemberVisibilityCanBePrivate", "unused")
class EventConstraintLayout(mContext: Context, attrs: AttributeSet?, defStyleAttr: Int) :
    ConstraintLayout(mContext, attrs, defStyleAttr) {
    constructor(mContext: Context, attrs: AttributeSet?) : this(mContext, attrs, 0)
    constructor(mContext: Context) : this(mContext, null, 0)

    //用于判断方向
    private var interceptStartX = 0f
    private var interceptStartY = 0f
    private var dispatchStartX = 0f
    private var dispatchStartY = 0f

    //是否进行了滑动
    private var isMoved = false

    //控制事件拦截 若子View调用了parent.requestDisallowInterceptTouchEvent(true) 拦截将不生效
    //向上拦截事件
    var interceptUp: Boolean = false

    //向下拦截事件
    var interceptDown: Boolean = false

    //向左拦截事件
    var interceptLeft: Boolean = false

    //向右拦截事件
    var interceptRight: Boolean = false

    //垂直拦截事件
    var interceptVertical: Boolean = false

    //水平拦截事件
    var interceptHorizontal: Boolean = false

    //是否启用事件获取 默认启用 将优先取得事件 无论父级是否拦截事件 不需要本身或子View响应某方向事件时 将对应方向置为false即可
    var enableHandled: Boolean = true

    //向上获取事件
    var handledUp: Boolean = true

    //向下获取事件
    var handledDown: Boolean = true

    //向左获取事件
    var handledLeft: Boolean = true

    //向右获取事件
    var handledRight: Boolean = true

    //垂直获取事件
    var handledVertical: Boolean = true

    //水平获取事件
    var handledHorizontal: Boolean = true

    //滑动事件方向标志
    companion object {
        const val directionHorizontal = 0
        const val directionVertical = 1
        const val directionUp = 2
        const val directionDown = 3
        const val directionLeft = 4
        const val directionRight = 5
        const val start = 6
        const val end = 7
        const val click = 8
    }

    fun getDirectionStr(direction: Int): String {
        return when (direction) {
            0 -> "<---->"
            1 -> "↑↓"
            2 -> "↑"
            3 -> "↓"
            4 -> "<--"
            5 -> "-->"
            6 -> ">>"
            7 -> "||"
            else -> ""
        }
    }

    //用于计算滑动距离
    private var eventStartX = 0f
    private var eventStartY = 0f

    //事件监听
    private var onHandleEventListener: ((direction: Int, dx: Float, dy: Float, isHandled: Boolean) -> Unit)? =
        null

    fun setOnHandleEventListener(onHandleEventListener: (direction: Int, dx: Float, dy: Float, isHandled: Boolean) -> Unit) {
        this.onHandleEventListener = onHandleEventListener
    }

    /**
     * 控制事件分发
     */
    override fun dispatchTouchEvent(ev: MotionEvent?): Boolean {
        when (ev?.action) {
            MotionEvent.ACTION_DOWN -> {
                dispatchStartX = ev.rawX
                dispatchStartY = ev.rawY
                eventStartX = ev.rawX
                eventStartY = ev.rawY
                isMoved = false
                //当与外部可滑动组件嵌套时，this优先取得事件
                disallowParentIntercept(enableHandled)
                onHandleEventListener?.invoke(start, 0f, 0f, true)
            }

            MotionEvent.ACTION_MOVE -> {
                val dx = ev.rawX - eventStartX
                val dy = ev.rawY - eventStartY
                val offsetX = ev.rawX - dispatchStartX
                val offsetY = ev.rawY - dispatchStartY
                val deltaX = abs(offsetX)
                val deltaY = abs(offsetY)
                if (deltaX > 0 || deltaY > 0) isMoved = true
                //水平事件
                if (deltaX > deltaY) {
                    if (!handledHorizontal) disallowParentIntercept(false)
                    //XLog.i("----->Handle: <----> $handledHorizontal")
                    onHandleEventListener?.invoke(directionHorizontal, dx, dy, handledHorizontal)
                }
                //垂直事件
                if (deltaY > deltaX) {
                    if (!handledVertical) disallowParentIntercept(false)
                    //XLog.i("----->Handle: ↑↓ $handledVertical")
                    onHandleEventListener?.invoke(directionVertical, dx, dy, handledVertical)
                }
                //右滑事件
                if (deltaX > deltaY && offsetX > 0) {
                    if (!handledRight || !handledHorizontal) disallowParentIntercept(false)
                    //XLog.i("----->Handle: --> $handledRight")
                    onHandleEventListener?.invoke(directionRight, dx, dy, handledRight)
                }
                //左滑事件
                if (deltaX > deltaY && offsetX < 0) {
                    if (!handledLeft || !handledHorizontal) disallowParentIntercept(false)
                    //XLog.i("----->Handle: <-- $handledLeft")
                    onHandleEventListener?.invoke(directionLeft, dx, dy, handledLeft)
                }
                //下滑事件
                if (deltaY > deltaX && offsetY > 0) {
                    if (!handledDown || !handledVertical) disallowParentIntercept(false)
                    //XLog.i("----->Handle: ↓ $handledDown")
                    onHandleEventListener?.invoke(directionDown, dx, dy, handledDown)
                }
                //上滑事件
                if (deltaY > deltaX && offsetY < 0) {
                    if (!handledUp || !handledVertical) disallowParentIntercept(false)
                    //XLog.i("----->Handle: ↑ $handledUp")
                    onHandleEventListener?.invoke(directionUp, dx, dy, handledUp)
                }
                eventStartX = ev.rawX
                eventStartY = ev.rawY
            }

            MotionEvent.ACTION_UP, MotionEvent.ACTION_CANCEL -> {
                //抬起时主动交还事件
                disallowParentIntercept(false)
                onHandleEventListener?.invoke(if (isMoved) end else click, 0f, 0f, false)
            }
        }
        return super.dispatchTouchEvent(ev)
    }

    /**
     * 所有父级控件的事件启用或禁用拦截
     */
    private var viewParent: ViewParent? = null
    private fun disallowParentIntercept(disallow: Boolean) {
        if (viewParent == null) viewParent = parent
        viewParent?.requestDisallowInterceptTouchEvent(disallow)
        if (viewParent?.parent != null && viewParent?.parent?.javaClass?.name != "com.android.internal.policy.DecorView") {
            //递归调用将所有父级控件(直到DecorView)的事件拦截都禁用或启用
            viewParent = viewParent?.parent
            disallowParentIntercept(disallow)
        } else {
            //递归结束恢复到第一层parent
            viewParent = parent
        }
    }

    /**
     * 控制事件拦截
     */
    override fun onInterceptTouchEvent(ev: MotionEvent?): Boolean {
        when (ev?.action) {
            MotionEvent.ACTION_DOWN -> {
                interceptStartX = ev.rawX
                interceptStartY = ev.rawY
            }

            MotionEvent.ACTION_MOVE -> {
                val offsetX = ev.rawX - interceptStartX
                val offsetY = ev.rawY - interceptStartY
                val deltaX = abs(offsetX)
                val deltaY = abs(offsetY)
                //水平滑动拦截事件
                if (deltaX > deltaY && interceptHorizontal) {
                    return true
                }
                //垂直滑动拦截事件
                if (deltaY > deltaX && interceptVertical) {
                    return true
                }
                //右滑拦截事件
                if (deltaX > deltaY && offsetX > 0 && interceptRight) {
                    return true
                }
                //左滑拦截事件
                if (deltaX > deltaY && offsetX < 0 && interceptLeft) {
                    return true
                }
                //下滑拦截事件
                if (deltaY > deltaX && offsetY > 0 && interceptDown) {
                    return true
                }
                //上滑拦截事件
                if (deltaY > deltaX && offsetY < 0 && interceptUp) {
                    return true
                }

            }

            MotionEvent.ACTION_UP -> {
            }
        }
        return super.onInterceptTouchEvent(ev)
    }

}